---
title: 'Google Authentication: Cypress Guide'
sidebar_label: 'Google Authentication'
description: 'Secure testing with seamless integration of Google Authentication, ensuring reliable and protected test scenarios'
---

<ProductHeading product="app" />

# Google Authentication

:::info

##### <Icon name="question-circle" color="#4BBFD2" /> What you'll learn

- How to set up Cypress to test authentication with Google
- How to set Google app credentials in Cypress
- How to create a custom command for Google authentication
- How to adapt a Google app for testing

:::

The technique we'll use for testing is to use the
[Google OAuth 2.0 Playground](https://developers.google.com/oauthplayground) to
create a refresh token that can be exchanged for an access token and id token
during the testing phase.

## Google Project and Application Setup

First, a [Google](https://google.com) project is required. If you don't already
have a project, you can create one using the
[Google Cloud Console](https://console.cloud.google.com). More information is
available in the
[Google Cloud APIs Getting Started](https://cloud.google.com/apis/docs/getting-started#creating_a_google_project).

Next, use the [Google API Console](https://console.developers.google.com/APIs)
to [create credentials](https://console.developers.google.com/apis/credentials)
for your web application. In the top navigation, click `Create Credentials` and
choose `OAuth client ID`.

On the `Create OAuth client ID` page, enter the following:

- **Application Type:** Web Application
- **Name:** Your Web Application Name
- **Authorized JavaScript origins:** `http://localhost:3000`
- **Authorized redirect URIs:** `http://localhost:3000/callback` and
  `https://developers.google.com/oauthplayground`

Once saved, note the **client ID** and **client secret**. You can find these under the
"OAuth 2.0 Client IDs" on the
[Google API Credentials](https://console.developers.google.com/apis/credentials)
page.

## Using the Google OAuth 2.0 Playground to Create Testing Credentials

:::info

The refresh token from this process is unique to the authenticated Google user.
This process must be repeated for each user intended for testing.

:::

Visit the
[Google OAuth 2.0 Playground](https://developers.google.com/oauthplayground).
Click the <Icon name="cog" /> icon in the upper right corner to reveal a
`OAuth 2.0 configuration` panel. In this panel set the following:

- **OAuth flow**: Server-side
- **Access type**: Offline
- Check `Use your own OAuth credentials`.
- **OAuth Client ID**: Your Google Application Client ID
- **OAuth Client secret**: Your Google Application Client Secret

Select the Google APIs needed for your application under
**Step 1 (Select & authorize APIs)**, including the
`https://www.googleapis.com/auth/userinfo.profile` endpoint under
**Google OAuth2 API v2** at a minimum. Click **Authorize APIs**.

Next, sign in with Google credentials to your test Google user account. You'll be redirected back to the
[Google OAuth 2.0 Playground](https://developers.google.com/oauthplayground)
under **Step 2 (Exchange authorization code for tokens)**. Click the
**Exchange authorization code for token** button.

You'll be taken to **Step 3 (Configure request to API)**. Note the returned
refresh token to be used with testing.

## Setting Google app credentials in Cypress

To have access to test user credentials within our tests we need to configure
Cypress to use the [Google](https://google.com) environment variables set in the
`.env` file.

```jsx title=".env"
REACT_APP_GOOGLE_CLIENTID = 'your-client-id'
REACT_APP_GOOGLE_CLIENT_SECRET = 'your-client-secret'
GOOGLE_REFRESH_TOKEN = 'your-refresh-token'
```

:::cypress-config-example

```js
// Populate process.env with values from .env file
require('dotenv').config()
```

```js
{
  env: {
    googleRefreshToken: process.env.GOOGLE_REFRESH_TOKEN,
    googleClientId: process.env.REACT_APP_GOOGLE_CLIENTID,
    googleClientSecret: process.env.REACT_APP_GOOGLE_CLIENT_SECRET,
  },
}
```

:::

## Custom Command for Google Authentication

Next, we'll write a command named `loginByGoogleApi` to perform a programmatic
login into Google and set an item in `localStorage` with the
authenticated users details, which we'll use in our application code to verify
we are authenticated under test.

The `loginByGoogleApi` command will execute the following steps:

1. Use the refresh token from the
   [Google OAuth 2.0 Playground](https://developers.google.com/oauthplayground)
   to perform the programmatic login, exchanging the refresh token for an
   `access_token`.
2. Use the `access_token` returned to get the Google User profile.
3. Finally the `googleCypress` localStorage item is set with the `access token`
   and user profile.

```jsx title="cypress/support/commands.js"
Cypress.Commands.add('loginByGoogleApi', () => {
  cy.log('Logging in to Google')
  cy.request({
    method: 'POST',
    url: 'https://www.googleapis.com/oauth2/v4/token',
    body: {
      grant_type: 'refresh_token',
      client_id: Cypress.env('googleClientId'),
      client_secret: Cypress.env('googleClientSecret'),
      refresh_token: Cypress.env('googleRefreshToken'),
    },
  }).then(({ body }) => {
    const { access_token, id_token } = body

    cy.request({
      method: 'GET',
      url: 'https://www.googleapis.com/oauth2/v3/userinfo',
      headers: { Authorization: `Bearer ${access_token}` },
    }).then(({ body }) => {
      cy.log(body)
      const userItem = {
        token: id_token,
        user: {
          googleId: body.sub,
          email: body.email,
          givenName: body.given_name,
          familyName: body.family_name,
          imageUrl: body.picture,
        },
      }

      window.localStorage.setItem('googleCypress', JSON.stringify(userItem))
      cy.visit('/')
    })
  })
})
```

With our Google app setup properly, necessary environment variables in place,
and our `loginByGoogleApi` command implemented, we'll be able to authenticate
with Google while our app is under test. Below is a test to login as a user via
Google, complete the onboarding process and logout.

:::info

<strong>Try it out</strong>

The
[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/google.spec.ts)
is in the <Icon name="github" inline="true" contentType="rwa" />.

:::

```jsx title="auth.cy.js"
describe('Google', function () {
  beforeEach(function () {
    cy.task('db:seed')
    cy.loginByGoogleApi()
  })

  it('shows onboarding', function () {
    cy.contains('Get Started').should('be.visible')
  })
})
```

## Adapting a Google App for Testing

:::info

<strong>Note</strong>

The previous sections focused on the recommended Google authentication practice
within Cypress tests. To use this practice it's assumed you're testing an app
appropriately built or adapted to use Google.

The following sections provides guidance on building or adapting an app to use
Google authentication.

:::

The <Icon name="github" inline="true" contentType="rwa" /> is
used and provides configuration and runnable code for both the React SPA and the
Express back end.

The front end uses the
[react-google-login component](https://github.com/anthonyjgrove/react-google-login)
and the back end uses [express-jwt](https://github.com/auth0/express-jwt) to
validate the JWT provided by Google.

:::info

Use the `yarn dev:google` command when starting the
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app).

:::

### Adapting the back end

In order to validate API requests from the frontend, we install
[express-jwt](https://github.com/auth0/express-jwt) and
[jwks-rsa](https://github.com/auth0/node-jwks-rsa) and configure validation for
JWT's from Google.

```jsx title='backend/helpers.ts'
import jwt from 'express-jwt'
import jwksRsa from 'jwks-rsa'

dotenv.config()
const googleJwtConfig = {
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: 'https://www.googleapis.com/oauth2/v3/certs',
  }),
  // Validate the audience and the issuer.
  audience: process.env.REACT_APP_GOOGLE_CLIENTID,
  issuer: 'accounts.google.com',
  algorithms: ['RS256'],
}
```

Next, we'll define an Express middleware function to be use in our routes to
verify the Google JWT sent by the front end API requests
as the `Bearer` token.

```jsx title='backend/helpers.ts'
// ...
export const checkJwt = jwt(googleJwtConfig).unless({ path: ['/testData/*'] })
```

Once this helper is defined, we can use globally to apply to all routes:

```jsx title='backend/app.ts'
// initial imports ...
import { checkJwt } from './helpers'

// ...
if (process.env.REACT_APP_GOOGLE) {
  app.use(checkJwt)
}
// routes ...
```

### Adapting the front end

We need to update our front end React app to allow for authentication with
Google. As mentioned above, the front end uses the
[react-google-login component](https://github.com/anthonyjgrove/react-google-login)
to perform the login.

First, we create an `AppGoogle.tsx` container to render our application as it is
authenticated with Google. The component is identical to
the `App.tsx` component, but has the addition of a `GoogleLogin` component in
place of the original Sign Up and Sign In components.

A `useGoogleLogin` hook is added to send a `GOOGLE` event with the `user` and
`token` objects to work with the existing authentication layer
(`authMachine.ts`).

:::info

The full
[AppGoogle.tsx component](https://github.com/cypress-io/cypress-realworld-app/blob/develop/src/containers/AppGoogle.tsx)
is in the <Icon name="github" inline="true" contentType="rwa" />.

:::

```tsx title='containers/AppGoogle.tsx'
// initial imports ...
import { GoogleLogin, useGoogleLogin } from 'react-google-login'
// ...
const AppGoogle = () => {
  // ...
  useGoogleLogin({
    clientId: process.env.REACT_APP_GOOGLE_CLIENTID!,
    onSuccess: (res) => {
      authService.send('GOOGLE', { user: res.profileObj, token: res.tokenId })
    },
    cookiePolicy: 'single_host_origin',
    isSignedIn: true,
  })
  // ...
  const isLoggedIn =
    isAuthenticated &&
    (authState.matches('authorized') ||
      authState.matches('refreshing') ||
      authState.matches('updating'))
  return (
    <div className={classes.root}>
      // ...
      {authState.matches('unauthorized') && (
        <Container component="main" maxWidth="xs">
          <CssBaseline />
          <div className={classes.paper}>
            <GoogleLogin
              clientId={process.env.REACT_APP_GOOGLE_CLIENTID!}
              buttonText="Login"
              cookiePolicy={'single_host_origin'}
            />
          </div>
        </Container>
      )}
    </div>
  )
}
export default AppGoogle
```

Next, we update our entry point (`index.tsx`) to conditionally load the
`AppGoogle` component if we start the application with the `REACT_APP_GOOGLE`
environment variable set to `true`.

```tsx title='src/index.tsx'
import React from 'react'
import ReactDOM from 'react-dom'
import { Router } from 'react-router-dom'
import { history } from './utils/historyUtils'
import App from './containers/App'
import AppGoogle from './containers/AppGoogle'
import { createMuiTheme, ThemeProvider } from '@material-ui/core'
const theme = createMuiTheme({
  palette: {
    secondary: {
      main: '#fff',
    },
  },
})
ReactDOM.render(
  <Router history={history}>
    <ThemeProvider theme={theme}>
      {process.env.REACT_APP_GOOGLE ? <AppGoogle /> : <App />}
    </ThemeProvider>
  </Router>,
  document.getElementById('root')
)
```
